package com.flow.engine.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.flow.engine.entity.FlowAuditUser;
import com.flow.engine.entity.FlowNode;
import com.flow.engine.entity.User;
import com.flow.engine.handle.FlowEngineEndHandler;
import com.flow.engine.handle.FlowEngineFailHandler;
import com.flow.engine.handle.FlowEnginePassHandler;
import com.flow.engine.handle.SendSMSHandler;
import com.flow.engine.enums.simple.Condition;
import com.flow.engine.enums.standard.ApprovalState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author ly163
 */
@Service
public class FlowEngineService {

    @Autowired
    private FlowNodeService flowNodeService;

    @Autowired
    private FlowAuditUserService flowAuditUserService;


    public Boolean auditReject(FlowNode flowNode, User user, FlowEngineFailHandler failHandle) {
        flowNode.setApprovalState(ApprovalState.REJECT);
        flowNodeService.updateById(flowNode);
        flowNodeService.update(Wrappers.<FlowNode>lambdaUpdate()
                .eq(FlowNode::getFlowId, flowNode.getFlowId())
                .isNull(FlowNode::getApprovalState)
                .set(FlowNode::getRemark, flowNode.getFlowId())
                .set(FlowNode::getApprovalState, ApprovalState._REJECT)
        );
        failHandle.fail(user, flowNode.getRemark());
        return Boolean.TRUE;
    }


    public Boolean auditPass(FlowNode flowNode, User user, FlowEngineEndHandler endHandle, FlowEnginePassHandler passHandle, SendSMSHandler sendSMSHandler) {
        Long currentNodeId = flowNode.getId();
        List<Long> parentIds = flowNode.getParentIds();
        AtomicReference<Boolean> notify = new AtomicReference<>(Boolean.TRUE);
        String currentCondition = flowNode.getCurrentCondition();

        if (Condition.OR.name().equals(currentCondition)) {
            flowAuditUserService.updateByFlowNodeId(currentNodeId, user, "remark", ApprovalState.PASS, ApprovalState._PASS);
            processBrotherNode(parentIds, currentNodeId, notify);
        } else {
            flowAuditUserService.updateByFlowNodeIdAndAuditUserId(currentNodeId, user.getId(), ApprovalState.PASS, "审核通过");
            List<FlowAuditUser> flowAuditUsers = flowAuditUserService.queryByFlowNodeId(currentNodeId);
            if (flowAuditUsers.size() > 1
                    &&
                !CollectionUtils.isEmpty(flowAuditUsers.stream().filter(item -> (item.getApprovalState() == null) && !item.getAuditUserId().equals(user.getId())).toList())) {
                    notify.set(Boolean.FALSE);
            }
        }
        if (!notify.get()) {
            return true;
        }
        flowNodeService.updateById(flowNode);
        passHandle.pass(flowNode);
        List<Long> nextNodes = flowNode.getNextIds();
        if (!CollectionUtils.isEmpty(nextNodes)) {
            flowAuditUserService.queryByFlowNodeIds(nextNodes)
                    .forEach(flowAuditUser -> sendSMSHandler
                            .sendSMS(flowNode.getFlowId(), flowAuditUser.getAuditUserId(), user, "当前节点审批通过，进入下一个审批节点"));
        } else {
            endHandle.end(user);
        }

        return Boolean.TRUE;
    }

    private void processBrotherNode(List<Long> parentIds, Long currentNodeId, AtomicReference<Boolean> notify) {
        if (CollectionUtils.isEmpty(parentIds)) {
            return;
        }
        for (Long parentId : parentIds) {
            FlowNode parent = flowNodeService.getById(parentId);
            List<Long> brotherNodeIds = parent.getNextIds();
            brotherNodeIds.remove(currentNodeId);
            String parentCondition = parent.getNextCondition();
            for (Long brotherId : brotherNodeIds) {
                FlowNode brotherNode = flowNodeService.getById(brotherId);
                if (Objects.equals(parentCondition, Condition.AND.name())
                        && ApprovalState.PASS != brotherNode.getApprovalState()) {
                    notify.set(Boolean.FALSE);
                    break;
                }
                if (Objects.equals(parentCondition, Condition.OR.name())) {
                    brotherNode.setApprovalState(ApprovalState._PASS);
                }
            }
        }
    }

}
